package net.mhelvens.deltaprofiles;

import java.util.HashSet;
import java.util.Set;

import android.content.ClipData;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.DragEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.DragShadowBuilder;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

public class RuleEditConditionFragment extends Fragment {
	private static final String TAG = RuleEditConditionFragment.class.getSimpleName();
	
	private Rule mRule;
	
	private ImageView  formulaBackground;
	private FlowLayout formula;
	
	private TextView   logicalAnd;
	private TextView   logicalOr;
	private TextView   logicalNot;
	private TextView   logicalTrue;
	private TextView   logicalFalse;

	private ListView   conditionTypeList;
	private TextView   conditionTypeListEmpty;
	
	Set<View> editViews;
	
	private class ConditionDragListener implements View.OnLongClickListener {
		private ClipData mClipData;
		
		private ConditionDragListener(ClipData clipData) {
			mClipData = clipData;
		}
		
		public boolean onLongClick(View v) {
			// TODO: custom drag shadow
			
			startEditMode();
			
			v.startDrag(mClipData, new DragShadowBuilder(v), null, 0);
			
			return true;
		}
	}
	
	public void collectViews() {
		formulaBackground = (ImageView)  getActivity().findViewById(R.id.formula_background);
		formula           = (FlowLayout) getActivity().findViewById(R.id.formula);
		
		logicalAnd   = (TextView) getActivity().findViewById(R.id.logical_and  );
		logicalOr    = (TextView) getActivity().findViewById(R.id.logical_or   );
		logicalNot   = (TextView) getActivity().findViewById(R.id.logical_not  );
		logicalTrue  = (TextView) getActivity().findViewById(R.id.logical_true );
		logicalFalse = (TextView) getActivity().findViewById(R.id.logical_false);

		conditionTypeList      = (ListView) getActivity().findViewById(R.id.condition_type_list      );
		conditionTypeListEmpty = (TextView) getActivity().findViewById(R.id.condition_type_list_empty);
	}

	private void startEditMode() {
		formulaBackground.setImageDrawable(getResources().getDrawable(R.drawable.green_indicator));
		for (View editView: editViews)
			editView.setVisibility(View.VISIBLE);
	}

	private void stopEditMode() {
		formulaBackground.setImageDrawable(null);
		for (View editView: editViews)
			editView.setVisibility(View.GONE);
	}
	
	public void setupViews() {
		//// This listener is responsible for setting up and breaking down
		//// the the edit view (not just the background).
		//
		formulaBackground.setOnDragListener(new View.OnDragListener() {
			public boolean onDrag(View v, DragEvent event) {
				switch(event.getAction()) {
					
					case DragEvent.ACTION_DRAG_STARTED: {
					} return true;
					
					case DragEvent.ACTION_DRAG_ENDED: {
						stopEditMode();
					} return true;
					
				}
				
				return false;
			}
		});
		
		logicalAnd  .setOnLongClickListener(new ConditionDragListener(ClipData.newRawUri("Logical 'and'"   , LogicalAndCondition.static_uri())));
		logicalOr   .setOnLongClickListener(new ConditionDragListener(ClipData.newRawUri("Logical 'or'"    , LogicalOrCondition .static_uri())));
		logicalNot  .setOnLongClickListener(new ConditionDragListener(ClipData.newRawUri("Logical 'not'"   , LogicalNotCondition.static_uri())));
		logicalTrue .setOnLongClickListener(new ConditionDragListener(ClipData.newRawUri("Logical 'true' " , LogicalTrue        .static_uri())));
		logicalFalse.setOnLongClickListener(new ConditionDragListener(ClipData.newRawUri("Logical 'false' ", LogicalFalse       .static_uri())));
		
		conditionTypeList.setEmptyView(conditionTypeListEmpty);
		conditionTypeList.setAdapter(ConditionType.allListed());
		
		conditionTypeList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
			public boolean onItemLongClick(AdapterView<?> v1, View row, int index, long id) {
				// TODO: custom drag shadow
				
				startEditMode();
				
				ConditionType ct = ConditionType.get(id);
				
				row.startDrag(
					ClipData.newRawUri(ct.description(), ct.sourceUri()),
					new DragShadowBuilder(row), null, 0
				);
				
				return true;
			}
		});
	}
	
	public void refreshViews() {
		// replacing the entire formula is rather drastic
		// TODO: refresh more incrementally (or perhaps it's just fast enough)
		formula.removeAllViews();
		if (mRule.condition() == null) {
			final ImageView initialDropTarget = (ImageView) ((LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.drop_target, formula, false);
			initialDropTarget.setVisibility(View.GONE);
			editViews.add(initialDropTarget);
			formula.addView(initialDropTarget);
			initialDropTarget.setOnDragListener(new View.OnDragListener() {
				public boolean onDrag(View v, DragEvent event) {
					switch(event.getAction()) {
						
						case DragEvent.ACTION_DRAG_STARTED: {
							return true;
						}
						
						case DragEvent.ACTION_DRAG_ENTERED: {
							initialDropTarget.setImageDrawable(getResources().getDrawable(R.drawable.drop_target_open));
							return true;
						}
						
						case DragEvent.ACTION_DRAG_EXITED: {
							initialDropTarget.setImageDrawable(getResources().getDrawable(R.drawable.drop_target_closed));
							return true;
						}
						
						case DragEvent.ACTION_DROP: {
							try {
								Condition.create(event.getClipData().getItemAt(0).getUri().toString(), mRule);
								refreshViews();
							} catch (Exception e) {
								Log.e(TAG, "Error instantiating new condition", e);
								return false;
							}
						}
						
						default: {
							return false;
						}
						
					}
				}
			});
		} else {
			mRule.condition().buildFormula(new Condition.OnChanged() {
				public void notifyView() {
					refreshViews();
				}
			}, new Condition.FormulaViewAdapter() {
				public void appendView(View v) {
					formula.addView(v);
				}
				
				public void appendEditView(View v) {
					formula.addView(v);
					v.setVisibility(View.GONE);
					editViews.add(v);
				}
			}, formula);
		}
	}
	
	RuleEditConditionFragment(Rule rule) {
		mRule = rule;
	}
	
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		return inflater.inflate(R.layout.rule_edit_condition, container, false);
	}

	@Override
	public void onViewCreated(View view, Bundle savedInstanceState) {
		super.onViewCreated(view, savedInstanceState);
		
		editViews = new HashSet<View>();
		
		collectViews();
		setupViews();
		refreshViews();
	}
	
}
